package com.fwtai.pay.wechat.auth;

import com.fwtai.pay.wechat.Credentials;
import com.fwtai.pay.wechat.WechatPayUploadHttpPost;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.client.methods.HttpRequestWrapper;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;

public class WechatPay2Credentials implements Credentials {

  protected static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  protected static final SecureRandom RANDOM = new SecureRandom();
  protected final String merchantId;
  protected final Signer signer;

  public WechatPay2Credentials(final String merchantId,final Signer signer) {
    this.merchantId = merchantId;
    this.signer = signer;
  }

  public String getMerchantId() {
    return merchantId;
  }

  protected long generateTimestamp() {
    return System.currentTimeMillis() / 1000;
  }

  protected String generateNonceStr() {
    final char[] nonceChars = new char[32];
    for (int index = 0; index < nonceChars.length; ++index) {
      nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
    }
    return new String(nonceChars);
  }

  @Override
  public final String getSchema() {
    return "WECHATPAY2-SHA256-RSA2048";
  }

  @Override
  public final String getToken(final HttpRequestWrapper request) throws IOException {
    final String nonceStr = generateNonceStr();
    final long timestamp = generateTimestamp();
    final String message = buildMessage(nonceStr, timestamp, request);
    final Signer.SignatureResult signature = signer.sign(message.getBytes(StandardCharsets.UTF_8));
    final String token = "mchid=\"" + getMerchantId() + "\","
      + "nonce_str=\"" + nonceStr + "\","
      + "timestamp=\"" + timestamp + "\","
      + "serial_no=\"" + signature.certificateSerialNumber + "\","
      + "signature=\"" + signature.sign + "\"";
    return token;
  }

  protected String buildMessage(final String nonce,final long timestamp,final HttpRequestWrapper request) throws IOException {
    final URI uri = request.getURI();
    String canonicalUrl = uri.getRawPath();
    if (uri.getQuery() != null) {
      canonicalUrl += "?" + uri.getRawQuery();
    }
    String body = "";
    // PATCH,POST,PUT
    if (request.getOriginal() instanceof WechatPayUploadHttpPost) {
      body = ((WechatPayUploadHttpPost) request.getOriginal()).getMeta();
    } else if (request instanceof HttpEntityEnclosingRequest) {
      body = EntityUtils.toString(((HttpEntityEnclosingRequest) request).getEntity(), StandardCharsets.UTF_8);
    }

    return request.getRequestLine().getMethod() + "\n"
      + canonicalUrl + "\n"
      + timestamp + "\n"
      + nonce + "\n"
      + body + "\n";
  }
}